#include "ImguiLayer.h"
#include <SEUi/SEUi.h>
#include <SEUi/Backends/imgui_impl_sdl2.h>
#include <SEUi/Backends/imgui_impl_opengl3.h>
#include <SDL.h>
#include <SDL_opengl.h>
#include <SEDebug/Log/Log.h>
#include <SERender/Drive/Drive.h>
#include <ImGuizmo.h>

namespace SEngine
{
    void ImguiLayer::Attach()
    {
        m_window.eventSignal.AddSlot([this](SDL_Event & event) { this->OnEvent(event); return SlotState::Keep; });
        const char *glsl_version = "#version 330";
        // Setup Dear ImGui context
        IMGUI_CHECKVERSION();
        auto imguiContext = ImGui::CreateContext();

        ImGuiIO &io = ImGui::GetIO();
        (void)io;
        io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
        // io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;      // Enable Gamepad Controls
        io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
        // io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;         // Enable Multi-Viewport / Platform Windows
        // io.ConfigViewportsNoAutoMerge = true;
        // io.ConfigViewportsNoTaskBarIcon = true;
        io.IniFilename = nullptr;
        ImGui::LoadIniSettingsFromDisk("imgui.ini");

        // Setup Dear ImGui style
        // ImGui::StyleColorsDark();
        ImGui::StyleColorsClassic();
        // ImGui::StyleColorsLight();

        // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
        ImGuiStyle &style = ImGui::GetStyle();
        style.FrameRounding = 6.0f;
        style.FrameBorderSize = 1.0f;
        if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
        {
            style.WindowRounding = 0.0f;
            style.Colors[ImGuiCol_WindowBg].w = 1.0f;
        }

        // Setup Platform/Renderer backends
        ImGui_ImplSDL2_InitForOpenGL(m_window.GetWindow(), SDLWindow::g_glContext);
        ImGui_ImplOpenGL3_Init(glsl_version);
    }

    void ImguiLayer::Detach()
    {
        // Cleanup
        ImGui_ImplOpenGL3_Shutdown();
        ImGui_ImplSDL2_Shutdown();
        ImGui::DestroyContext();
    }

    void ImguiLayer::BeginFrame()
    {
        // Start the Dear ImGui frame
        ImGui_ImplOpenGL3_NewFrame();
        ImGui_ImplSDL2_NewFrame();
        ImGui::NewFrame();
        ImGuizmo::BeginFrame();
    }

    void ImguiLayer::EndFrame()
    {
        ImGuiIO &io = ImGui::GetIO();
        (void)io;
        // Rendering
        ImGui::Render();
        CurrentDrive().Clear(COLOR_BUFFER_BIT);
        ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

        // Update and Render additional Platform Windows
        // (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere.
        //  For this specific demo app we could also call SDL_GL_MakeCurrent(window, gl_context) directly)
        if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
        {
            SDL_Window *backup_current_window = SDL_GL_GetCurrentWindow();
            SDL_GLContext backup_current_context = SDL_GL_GetCurrentContext();
            ImGui::UpdatePlatformWindows();
            ImGui::RenderPlatformWindowsDefault();
            SDL_GL_MakeCurrent(backup_current_window, backup_current_context);
        }
    }

    void ImguiLayer::Update(int delta)
    {
        // ImGui::ShowDemoWindow();
    }

    void ImguiLayer::OnEvent(EventPtr event)
    {
        // Log::GetInstance().Debug(event->DebugName());
    }

    void ImguiLayer::OnEvent(SDL_Event &event)
    {
        ImGui_ImplSDL2_ProcessEvent(&event);
    }
} // namespace SEngine
